#
# GSTarget.py
# Created by Gerikes for GerikSpells
#

from CvPythonExtensions import *

gc = CyGlobalContext()

import GerikSpellsUtils
import GerikSpellsInterface

import math
import copy # For making clones of target infos

class GSBase:
    def __init__(self):
        self.m_pTargetInfoPolicy = None
        self.m_pTargetSelectCallback = None

        self.m_pTargetInfo = None
        
        self.m_pCacheAffectedList = None
        self.m_pCacheUnaffectedList = None

    def start(self, pTargetInfoPolicy, pTargetSelectCallback, pTargetList):
        self.m_pTargetInfoPolicy = pTargetInfoPolicy
        self.m_pTargetSelectCallback = pTargetSelectCallback
        self.m_pTargetInfo = copy.copy(self.m_pTargetInfoPolicy)

    def stop(self):
        self.undraw()
        self.m_pTargetInfoPolicy = None
        self.m_pTargetSelectCallback = None
        self.m_pTargetInfo = None

    def updateTarget(self, pTarget):
        self.m_pTargetInfo.setTarget(pTarget)
        pCastingGroup = GerikSpellsInterface.getCurrentSpell().getCastingGroup()
        pCastingPlot = GerikSpellsInterface.getCurrentSpell().getCastingPlot()

        pTargetLists = self.m_pTargetInfo.getSecondaryTargetList(pCastingGroup, pCastingPlot)
        self.m_pCacheAffectedList = pTargetLists[0]
        self.m_pCacheUnaffectedList = pTargetLists[1]

    def targetSelected(self, pTargetInfo):
        # Tells the next system to start.
        self.m_pTargetSelectCallback(pTargetInfo)


    def mouseOverPlot(self):
        raise NotImplementedError

    def getBars(self):
        return self.m_pTargetInfo.getBars()

    def parseTargetInfo(self):
        return self.m_pTargetInfo.parseInfo()

    def onUpdate(self):
        raise NotImplementedError

    def close(self):
        raise NotImplementedError



class GSPlot(GSBase):
    def __init__(self):
        GSBase.__init__(self)
        self.m_bShowRangeGraphics = False
        self.m_pRangePlotList = None
        
        self.m_szAffectedPlotColor = "COLOR_GREEN"
        self.m_fAffectedPlotAlpha = 1.0
        self.m_szUnaffectedPlotColor = "COLOR_WHITE"
        self.m_fUnaffectedPlotAlpha = 1.0
        self.m_szRangePlotColor = "COLOR_WHITE"
        self.m_fRangePlotAlpha = 0.4

        self.m_iAffectedPlotTexture = PlotStyles.PLOT_STYLE_BOX_OUTLINE
        self.m_iUnaffectedPlotTexture = PlotStyles.PLOT_STYLE_BOX_OUTLINE
        self.m_iRangePlotTexture = PlotStyles.PLOT_STYLE_TARGET

    # Range functions
    def getShowRangeGraphics(self):
        return self.m_bShowRangeGraphics

    def setShowRangeGraphics(self, bShow):
        self.m_bShowRangeGraphics = bShow        

    # Plot Colors & Alpha
    def getAffectedPlotColor(self):
        return self.m_szAffectedPlotColor

    def getAffectedPlotAlpha(self):
        return self.m_fAffectedPlotAlpha

    def setAffectedPlotColor(self, szColor, fAlpha):
        self.m_szAffectedPlotColor = szColor
        self.m_fAffectedPlotAlpha = fAlpha

    def getUnaffectedPlotColor(self):
        return self.m_szUnaffectedPlotColor

    def getUnaffectedAlpha(self):
        return self.m_fUnaffectedPlotAlpha

    def setUnaffectedPlotColor(self, szColor, fAlpha):
        self.m_szUnaffectedPlotColor = szColor
        self.m_fUnaffectedPlotAlpha = fAlpha

    def getRangePlotColor(self):
        return self.m_szRangePlotColor

    def getRangePlotAlpha(self):
        return self.m_szRangePlotAlpha

    def setRangePlotColor(self, szColor, fAlpha):
        self.m_szRangePlotColor = szColor
        self.m_fRangePlotAlpha = fAlpha

    # Plot textures
    def getAffectedPlotTexture(self):
        return self.m_iAffectedPlotTexture

    def setAffectedPlotTexture(self, iTexture):
        self.m_iAffectedPlotTexture = iTexture

    def getUnaffectedPlotTexture(self):
        return self.m_iUnaffectedPlotTexture

    def setUnaffectedPlotTexture(self, iTexture):
        self.m_iUnaffectedPlotTexture = iTexture

    def getRangeGraphicsTextureID(self):
        return self.m_iRangeGraphicsTextureID

    def setRangeGraphicsTextureID(self, iTextureID):
        self.m_iRangeGraphicsTextureID = iTextureID

    # The real juicy functions
    def start(self, pTargetInfoPolicy, pTargetSelectCallback, pTargetList): # pTargetList is range plot list
        GSBase.start(self, pTargetInfoPolicy, pTargetSelectCallback, pTargetList)
        self.m_pTargetInfo.setRangePlotList(pTargetList)
        GerikSpellsInterface.showPlotSelectScreen(self, self.m_pTargetInfo)

        # Show the range plots if required.
        if (self.getShowRangeGraphics()):
            pCurrentSpell = GerikSpellsInterface.getCurrentSpell()
            for pPlot in self.m_pTargetInfo.getRangePlotList(pCurrentSpell.getCastingGroup(), pCurrentSpell.getCastingPlot()):
                self.drawRangePlot(pPlot)

        # Forces the first plots to be drawn.
        self.mouseOverPlot()

    # GERIKESTODO: What are the differences here?
    def stop(self):
        self.undraw()
        GerikSpellsInterface.getPlotSelectScreen().close()

    def close(self):
        self.undraw()
        GerikSpellsInterface.getPlotSelectScreen().close()

    def mouseOverPlot(self):
        self.updateTarget(CyInterface().getMouseOverPlot())
        self.draw()

    # Drawing functions
    def draw(self):
        self.undrawTargets()

        for pPlot in self.m_pCacheUnaffectedList:
            self.drawUnaffectedPlot(pPlot)
            
        for pPlot in self.m_pCacheAffectedList:
            self.drawAffectedPlot(pPlot)

    def drawAffectedPlot(self, pPlot):
        CyEngine().addColoredPlotAlt(pPlot.getX(), pPlot.getY(), self.m_iAffectedPlotTexture, 2, self.m_szAffectedPlotColor, self.m_fAffectedPlotAlpha) # GERIKESTODO

    def drawUnaffectedPlot(self, pPlot):
        CyEngine().addColoredPlotAlt(pPlot.getX(), pPlot.getY(), self.m_iUnaffectedPlotTexture, 2, self.m_szUnaffectedPlotColor, self.m_fUnaffectedPlotAlpha) # GERIKESTODO

    def drawRangePlot(self, pPlot):
        CyEngine().addColoredPlotAlt(pPlot.getX(), pPlot.getY(), self.m_iRangePlotTexture, 0, self.m_szRangePlotColor, self.m_fRangePlotAlpha) # GERIKESTODO
        
    def undraw(self):
        self.undrawRange()
        self.undrawTargets()

    def undrawRange(self):
        CyEngine().clearColoredPlots(0) # GERIKESTODO

    def undrawTargets(self):
        CyEngine().clearColoredPlots(2) # GERIKESTODO





class GSPieMenu(GSBase):
    def __init__(self):
        GSBase.__init__(self)
        self.m_iFinalButtonDistanceFromCenter = 100
        self.m_iFinalButtonSize = 50
        self.m_pMakeListCallback = None
        self.m_iMaximumTargetsPerPage = 8

    def getButtonDistanceFromCenter(self):
        return self.m_iFinalButtonDistanceFromCenter
    
    def setButtonDistanceFromCenter(self, iDistance):
        self.m_iFinalButtonDistanceFromCenter = iDistance

    def getButtonSize(self):
        return self.m_iFinalButtonSize

    def setButtonSize(self, iSize):
        self.m_iFinalButtonSize = iSize

    def getMakePieMenuListCallback(self):
        return self.m_pMakeListCallback

    def setMakePieMenuListCallback(self, pCallback):
        self.m_pMakeListCallback = pCallback

    def getPieMenuMaximumPageSize(self):
        return self.m_iMaximumPageSize

    def setPieMenuMaximumTargetsPerPage(self, iMax):
        self.m_iMaximumTargetsPerPage = iMax

    def start(self, pTargetInfoPolicy, pTargetSelectCallback, pTargetList): # pTargetList is the 2D (paged) list of targets
        GSBase.start(self, pTargetInfoPolicy, pTargetSelectCallback, pTargetList)
        
        # Sets the interfacemode and begins to show the screen
        GerikSpellsInterface.setLocalInterfaceMode2()
        pFinalTargetList = GerikSpellsUtils.convertDataListIntoPages(pTargetList, self.m_iMaximumTargetsPerPage)
        GerikSpellsInterface.showPieMenuSelectScreen(self, pFinalTargetList)

    def stop(self):
        GerikSpellsInterface.getPieMenuSelectScreen().close()
        self.m_pTargetInfoPolicy = None
        self.m_pTargetSelectCallback = None
        self.m_pTargetInfo = None


    def mouseOverPlot(self):
        return

    def getTargetButtonDimensions(self, iTargetNumber, iNumTargetsOnPage, fAnimationPercent):
        if (iNumTargetsOnPage == 0):
            CvUtil.pyAssert(False, "Recieved empty page in pie menu item list (divide by zero imminent)")
            return 
        # Angle of seperation between each button from the center (in radians)
        fAngle = (2 * math.pi / float(iNumTargetsOnPage))

        # Radians from the top (pi / 2), for use in determining where to place this button
        # Prevent round-off error.
        fRad = 0.0
        if (iTargetNumber == 0):
            fRad = -math.pi / 2.0
        else:
            fRad = (-math.pi / 2.0) + (float(iTargetNumber) * fAngle)

        return (
            int(self.m_iFinalButtonDistanceFromCenter * math.cos(fRad)), # X offset
            int(self.m_iFinalButtonDistanceFromCenter * math.sin(fRad)), # Y offset
            self.m_iFinalButtonSize,
            self.m_iFinalButtonSize
            )

    def getTurnPageButtonDimensions(self, fAnimationPercent):
        return (0, 0, self.m_iFinalButtonSize, self.m_iFinalButtonSize)

    def getTurnPageButton(self):
        gc.getMissionInfo(gc.getInfoTypeForString("MISSION_SKIP")).getButton()

    def parseTargetInfo(self, iPageNum, iTargetNum, bOption):
        return GerikSpellsInterface.getPieMenuSelectScreen().m_pTargetList[iPageNum][iTargetNum].parseInfo(bOption)

    def close(self):
        GerikSpellsInterface.getPieMenuSelectScreen().close()
        
